package com.iisigroup.audf.statistics;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateUtils;
import org.robert.study.utils.Utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.iisigroup.audf.model.Audf1000;
import com.iisigroup.audf.model.CalculateTime;

public class Processor {
    private static Logger logger = LoggerFactory.getLogger(Processor.class);
    public List<Audf1000> initProcess(final File srcFile){
	final List<Audf1000> result = initProcessCoreV1(srcFile);	
	return result ; 
    }
    public Map<String,Map<String,List<Audf1000>>> groupByUserIdTaskCode(final List<Audf1000> srcList){
	final Map<String,Map<String,List<Audf1000>>> result = new HashMap<String,Map<String,List<Audf1000>>>();
	for(Audf1000 unit : srcList){
	    String userId = unit.getUserId();
	    String taskCode = unit.getTaskCode();
	    Map<String, List<Audf1000>> userMapData = result.get(userId);
	    if(userMapData == null ){
		userMapData = new HashMap<String, List<Audf1000>>();
	    }
	    List<Audf1000> taskList = userMapData.get(taskCode);
	    if(taskList == null){
		taskList = new ArrayList<Audf1000>();
	    }
	    taskList.add(unit);
	    userMapData.put(taskCode, taskList);
	    result.put(userId, userMapData);
	}
	return result;
    }
    public Audf1000 parseToUnit(final String origline){
	final String line =StringUtils.replace(origline, "\\,", "\n");
//	final String line = origline;
	Audf1000 result = new Audf1000();
	final String[] strArray = StringUtils.splitPreserveAllTokens(line,",");
//	final String[] strArray = this.byRegExpr(line);
	result.setSeqNo(strArray[0]);
	result.setTxId(strArray[1]);
	result.setSysName(strArray[2]);	
	result.setOpDatetime(strArray[3]);
	result.setTaskId(strArray[4]);
	result.setTaskCh(strArray[5]);
	result.setTaskCode(strArray[6]);
	result.setTaskName(strArray[7]);
	result.setServicesClass(strArray[8]);
	result.setServiceMethod(strArray[9]);
	result.setMethodType(strArray[10]);
	result.setStatus(strArray[11]);
	result.setRtnCode(strArray[12]);
	result.setRtnMsg(strArray[13]);
	result.setSiteId(strArray[14]);
	result.setRmSiteId(strArray[15]);
	result.setOfficeCode(strArray[16]);
	result.setUserId(strArray[17]);
	result.setUserName(strArray[18]);
	result.setUserIp(strArray[19]);
	
	try {
	    result.setExecTime(Float.parseFloat(strArray[20]));
	} catch (NumberFormatException e) {
	    logger.error("original input: {}",strArray[20]);
	    logger.error("original line: {}",line);	    
	}
	
	result.setPersonId(strArray[21]);
	result.setChg1m4m(strArray[22]);
	result.setParameter(strArray[23]);
	result.setResult(strArray[24]);
	result.setErrorType(strArray[25]);
	result.setFinalType(strArray[26]);
	try {
	    result.setOrgType(strArray[27]);
	} catch (Exception e) {
	    logger.error("original line: {}",line);
	    logger.error("original input size: {}",strArray.length);
	}
	return result;	
    }
    public  String[] byRegExpr(String line ){
	final String patternStr = "(\\w*)(([\\s|\\w|\\.]*\\\\,[\\s|\\w|\\.]*)*)";
	final Pattern pattern = Pattern.compile(patternStr);
	final Matcher matcher = pattern.matcher(line);
	final List<String> metadata = new ArrayList<String>();
	while(matcher.find()){
//	    final int groupCount = matcher.groupCount();
//	    for(int i = 0 ; i<=groupCount ;++i){
//		final String unit = matcher.group(i);
//		logger.info("group:{} value :{}",i,unit);
//	    }
	    String unit = matcher.group(0);
	    if(StringUtils.isNotBlank(unit)){
		 metadata.add(unit);
//		    logger.info(unit);
	    }
	   
	}
	String[] result = metadata.toArray(new String[]{});
	return result;
    }
    private List<Audf1000> initProcessCoreV1(final File srcFile){
	final List<Audf1000> result = new ArrayList<Audf1000>();	
	BufferedReader fr = null;
	try {
	     fr = new BufferedReader(new FileReader(srcFile));
	     while( fr.ready()){
		final String line = fr.readLine();

		try {
		    final Audf1000 unit = parseToUnit(line);
		    result.add(unit);
		} catch (Exception e) {
		    e.printStackTrace();
		}
	     }   
	    
	} catch (FileNotFoundException e) {
	    e.printStackTrace();
	} catch (IOException e) {
	    e.printStackTrace();
	}finally{
	    if(fr != null){
		try {
		    fr.close();
		} catch (IOException e) {
		    e.printStackTrace();
		}
	    }
	}	
	return result ; 
    }
    private List<Audf1000> initProcessCoreV2(final File srcFile){
	final List<Audf1000> result = new ArrayList<Audf1000>();	
	BufferedReader fr = null;
	try {
	     fr = new BufferedReader(new FileReader(srcFile));	
	     
	     final String line = fr.readLine();
	     final     Audf1000 unit = parseToUnit(line);
	     result.add(unit);
	} catch (FileNotFoundException e) {
	    e.printStackTrace();
	} catch (IOException e) {
	    e.printStackTrace();
	}finally{
	    if(fr != null){
		try {
		    fr.close();
		} catch (IOException e) {
		    e.printStackTrace();
		}
	    }
	}	
	return result ; 
    }
    /***
     * 可用於使用 
     * (1)非兼辦TxId--->saveTmp   calculate是true
     * (2)兼辦TxId ---->save     calculate是false   
     * @param includeHouseInputConcurrentPerson 包含輸入大簿當事人的時間
     * @param 
     * **/
    public void calculateL3TimeThroughManyFiles(final boolean calculate ,final boolean includeHouseInputConcurrentPerson ,final boolean includeHouseholdSvaeRldf,final File... listFiles){
	final SimpleDateFormat opsdf = new SimpleDateFormat("yyyyMMddHHmmssS");
	final SimpleDateFormat viewsdf = new SimpleDateFormat("mm:ss.SSS");
	final SimpleDateFormat sdf = new SimpleDateFormat("yyMMddHHmmssSSS");
	final SimpleDateFormat viewsdf2 = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
	
	final String[] tasks = { "RL01210", "RL01220", "RL01230", "RL01240", "RL01250", "RL01263", "RL01273", "RL01290", "RL012B0", "RL012E0", "RL012F0", "RL012H0",
		"RL01310", "RL01320", "RL01330", "RL01340", "RL01390", "RL02100", "RL02200", "RL02300", "RL02510", "RL02800", "RL02A10", "RL02D00", "RL02E00",
		"RL02F00"
	};
	
	for(final File srcFile : listFiles){
	    if(srcFile.isDirectory()){
		continue;
	    }
	    final List<String> outputList = new ArrayList<String>();
	    final  List<Audf1000> audf100List = initProcessCoreV1(srcFile);
	    final Map<String,List<Audf1000>>  txIdDataListMap =  categoryByTxIdL3operation(audf100List);
	    final Map<String,List<Audf1000>>  txIdDataListMapResult =   new HashMap<String,List<Audf1000>>();
	    for(String txId:txIdDataListMap.keySet()){
		if (judgeIsNeedProcess(txIdDataListMap.get(txId), tasks)) {
		    txIdDataListMapResult.put(txId, txIdDataListMap.get(txId));
		}
	    }
	    for(String txId:txIdDataListMapResult.keySet()){
		    if(txId.equalsIgnoreCase("TXXLRL1405091535521793")){
			System.out.println("....");
		    }
		final	List<Audf1000> audf1000List = txIdDataListMapResult.get(txId);
		final Map<String,List<Audf1000>>  taskCodeDataListMap=   new HashMap<String,List<Audf1000>>();
		for(Audf1000 unit : audf1000List){
		    String taskCode = unit.getTaskCode();
		    List<Audf1000> list = taskCodeDataListMap.get(taskCode);
		    if(list ==null){
			list = new 	ArrayList<Audf1000>();
		    }
		    list.add(unit);
		    taskCodeDataListMap.put(taskCode, list);
		}
		final Set<String> taskCodeSet = taskCodeDataListMap.keySet();
		int operationSeqSize = taskCodeSet.size() ;
		final List<CalculateTime> opertionList = new ArrayList<CalculateTime>();
		for (String taskCode : taskCodeSet) {
		    try {
			List<Audf1000> unitList = taskCodeDataListMap.get(taskCode);
			Date startTime = null;
			Date endTime = null;
			float lastExecTime = 0f;
			for (Audf1000 audf : unitList) {

			    final String methodName = audf.getServiceMethod().trim();
			    final String methodType =  audf.getMethodType().trim();

			    if(includeHouseInputConcurrentPerson){
				String initData = StringUtils.substring(txId, 6, 21);
				startTime = sdf.parse(initData);
			    } else {
				if (StringUtils.equalsIgnoreCase(methodName, "initOperationDTO")|
					StringUtils.equalsIgnoreCase(methodName, "readTransaction")
					) {
				    startTime = opsdf.parse(StringUtils.substring(audf.getOpDatetime(), 0, 15));
				}
			    }

			    if (StringUtils.equalsIgnoreCase(taskCode, "RL01310")) {
				if (StringUtils.equalsIgnoreCase(methodName, "processMoveinPersonSiteId")) {
				    endTime =  opsdf.parse(StringUtils.substring(audf.getOpDatetime(),0,15));
				    lastExecTime = audf.getExecTime();
				}
			    } else if (StringUtils.equalsIgnoreCase(taskCode, "RL02300")) {
				if (StringUtils.equalsIgnoreCase(methodName, "doSave")) {
				    endTime =  opsdf.parse(StringUtils.substring(audf.getOpDatetime(),0,15));
				    lastExecTime = audf.getExecTime();
				}
			    }else{
				if (    StringUtils.equalsIgnoreCase(methodName, "saveXldf")|
					StringUtils.equalsIgnoreCase(methodName, "saveXldfs")|
					StringUtils.equalsIgnoreCase(methodName, "saveXLDF") |
					StringUtils.equalsIgnoreCase(methodName, "saveRldf")|
					StringUtils.equalsIgnoreCase(methodName, "saveHouseholdContext")
					//saveHouseholdContext
					) {
				    endTime =  opsdf.parse(StringUtils.substring(audf.getOpDatetime(),0,15));
				    lastExecTime = audf.getExecTime();
				}
			    }
			    //無法使用annotation作為辨識是因為有些annotation是亂下的
			    
//			    if (StringUtils.equalsIgnoreCase(methodType, "SAVE") | StringUtils.equalsIgnoreCase(methodType, "SAVE2TEMP")
//				    | StringUtils.equalsIgnoreCase(methodType, "PRINT2TERM")
//				   ) {
//				endTime = opsdf.parse(StringUtils.substring(audf.getOpDatetime(), 0, 15));
//				lastExecTime = audf.getExecTime();
//			    }

			}

			if (endTime == null || startTime==null) {
			    continue;
			}
			final Date stdTime = DateUtils.addMilliseconds(new Date(endTime.getTime() - startTime.getTime()), (int) lastExecTime);
//			String line = String.format("%s | %s | %s", txId, taskCode, viewsdf.format(stdTime));
//			System.out.println(line);
			CalculateTime aCalculateTime =new CalculateTime();
			aCalculateTime.setSpendTime(stdTime);
			aCalculateTime.setTxId(txId);
			aCalculateTime.setTaskCode(taskCode);
			aCalculateTime.setEndTime(DateUtils.addMilliseconds(endTime,(int) lastExecTime));
			opertionList.add(aCalculateTime);
		    } catch (ParseException e) {
			e.printStackTrace();
		    }
		    
		}
		Collections.sort(opertionList, comparatorSortByEndTime);
		    
		//測試輸出
		for (CalculateTime unit : opertionList) {
		    try {
			Date txStarTime = sdf.parse(StringUtils.substring(txId, 6, 21));
	    
			String line = String.format("%s | %s | %s | %s | %s", txId, unit.getTaskCode(), viewsdf.format(unit.getSpendTime()), viewsdf2.format(unit.getEndTime()) , viewsdf2.format(txStarTime));
//			System.out.println(line);
//			outputList.add(line);
		    } catch (ParseException e) {
			e.printStackTrace();
		    }
		}
		//符合情境(1)非兼辦TxId--->saveTmp
		if (calculate && opertionList.size() > 0) {
		    CalculateTime unit = opertionList.get(0);
		    boolean householdMaintainLogic =opertionList.size()>1 && StringUtils.equals("RL00001", opertionList.get(1).getTaskCode()) && ArrayUtils.contains(tasks, unit.getTaskCode()) ;
		    boolean specialRegLogic = StringUtils.equals("RL02300", unit.getTaskCode());
		    if (!includeHouseholdSvaeRldf && ( specialRegLogic || householdMaintainLogic) ) {
			//不包含大簿存檔時間
			try {
			    Date txStarTime = sdf.parse(StringUtils.substring(txId, 6, 21));
			    // 非兼辦的計算邏輯
			    if(includeHouseInputConcurrentPerson){
				Date spdfTime = new Date(unit.getEndTime().getTime() - txStarTime.getTime());
				String line = String.format("%s | %s | %s", txId, unit.getTaskCode(), viewsdf.format(spdfTime));
				outputList.add(line);
			    }else{
				Date spdfTime = unit.getSpendTime();
				String line = String.format("%s | %s | %s", txId, unit.getTaskCode(), viewsdf.format(spdfTime));
				outputList.add(line);
			    }				
			} catch (ParseException e) {
			    e.printStackTrace();
			}
		    }else if(includeHouseholdSvaeRldf && ( specialRegLogic || householdMaintainLogic) && opertionList.size() > 1){
			//包含大簿存檔時間
			try {
			    Date txStarTime = sdf.parse(StringUtils.substring(txId, 6, 21));
			    // 非兼辦的計算邏輯
			    if(includeHouseInputConcurrentPerson){
				Date spdfTime = new Date(opertionList.get(1).getEndTime().getTime() - txStarTime.getTime());
				String line = String.format("%s | %s | %s", txId, unit.getTaskCode(), viewsdf.format(spdfTime));
				outputList.add(line);
			    }else{
				Date spdfTime = new Date(unit.getSpendTime().getTime() + opertionList.get(1).getSpendTime().getTime());
				String line = String.format("%s | %s | %s", txId, unit.getTaskCode(), viewsdf.format(spdfTime));
				outputList.add(line);
			    }				
			} catch (ParseException e) {
			    e.printStackTrace();
			}
		    }
		}
		    //兼辦計算邏輯
		if (!calculate && opertionList.size() > 0) {
		    boolean householdMaintainLogic = opertionList.size() > 1 && !StringUtils.equals("RL00001", opertionList.get(1).getTaskCode());
		    StringBuffer sbf = new StringBuffer();
		    if (householdMaintainLogic) {
			String spendTime = StringUtils.EMPTY;
			final List<String> taskCodeList = new ArrayList<String>();
			for (CalculateTime unit : opertionList) {
			    if (StringUtils.equalsIgnoreCase("RL00001", unit.getTaskCode())) {
				spendTime = viewsdf.format(unit.getSpendTime());
				break;
			    } else {
				taskCodeList.add(unit.getTaskCode());
			    }
			}
			if (!CollectionUtils.isEmpty(taskCodeList) && StringUtils.isNotBlank(spendTime)) {			    
			    String displayTaskCode = StringUtils.join(taskCodeList, "_");
			    String line = String.format("%s | %s | %s", txId, displayTaskCode, spendTime);
//			    System.out.println(line);
			    outputList.add(line);
			}

		    }
		}
	    }
	    try {
		File  dir = new File(srcFile.getParentFile().getAbsolutePath()+File.separator+"metadata");
		if(!dir.exists()){
		FileUtils.forceMkdir(dir);
		}
		File file =new File(dir.getAbsolutePath()+File.separator+srcFile.getName()+"_metadata");
		
		FileUtils.writeLines(file,   outputList);
	    } catch (IOException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	    }
   	}	
    }
    private boolean judgeIsNeedProcess(final List<Audf1000> data,final String[] tasks ){
	for(Audf1000 unit: data){
	    String taskCode =unit.getTaskCode();
	    if(ArrayUtils.contains(tasks, taskCode)){
		return true;
	    }
	}
	return false;
    }
    /***
     * 依照交易順序得到依時間順序排序的audf1000
     * 
     * */
    protected Map<String,List<Audf1000>> categoryByTxIdL3operation(final List<Audf1000> data ){
	final Map<String,List<Audf1000>> result = new HashMap<String,List<Audf1000>>();
	for(final Audf1000 unit : data ){
	    String txId = unit.getTxId();
	    List<Audf1000> list = result.get(txId);
	    if(list ==null){
		list = new ArrayList<Audf1000>();
	    }
	    list.add(unit);
	    result.put(txId, list);
	}
	for(String txId : result.keySet()){
	    List<Audf1000> list = result.get(txId);
	   
//	    if(txId.equalsIgnoreCase("TXXLRL1405091535521793")){
//		System.out.println("....");
//	    }
	    filterDuplicatedList(list);
	    Collections.sort(list,comparator);
	    result.put(txId, list);
	}
	return result;
    }
    private void filterDuplicatedList(final List<Audf1000> list){
	final Set<String> recordSet =new HashSet<String>();
//	for(int i=0;i<list.size(); ++i){
//	    Audf1000 type = list.get(i);
//	    final String seqNo = type.getSeqNo();
//	    if(recordSet.contains(seqNo)){
//		list.remove(i);
//		--i;
//	    }else{
//		recordSet.add(seqNo);
//	    }
//	}
	
	final	Iterator<Audf1000> iterator = list.iterator();
	while (iterator.hasNext()) {
	    Audf1000 type = iterator.next();
	    final String seqNo = type.getSeqNo();
	    if(recordSet.contains(seqNo)){
		 iterator.remove();
	    }else{
		recordSet.add(seqNo);
	    }	    
	}
    }
    private SortByOpDateTime comparator = new SortByOpDateTime();
    private SortByEndTime comparatorSortByEndTime = new SortByEndTime();
}
class SortByEndTime implements Comparator<CalculateTime> {
    public int compare(CalculateTime o1, CalculateTime o2) {
	return o1.getEndTime().compareTo(o2.getEndTime());
    }

}
class SortByOpDateTime implements Comparator<Audf1000> {
    public int compare(Audf1000 o1, Audf1000 o2) {
	return o1.getOpDatetime().compareTo(o2.getOpDatetime());
    }

}